package com.luming.tkbatis.annotation;

import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.RetentionPolicy.RUNTIME;


/**
 * 实体域对应的业务读写范围
 *
 * @author sunsulei
 */
@Target({ElementType.TYPE})
@Retention(RUNTIME)
public @interface BizCodeLevel {

    String UNDER_LINE = StrUtil.UNDERLINE;

    Level write() default Level.full;

    Level query() default Level.full;

    @AllArgsConstructor
    enum Level {
        /**
         * 完整的bizCode链路
         */
        full(-1),
        /**
         * 只取第一层
         */
        first(1),
        /**
         * todo
         */
        second(2),
        /**
         * todo
         */
        third(3),
        /**
         * 严格隔离,不继承
         */
        tenant(-1),
        /**
         * 忽略bizCode,一些关联表带上关联 id 查询时,没必要限制租户.但是得限制查询条件必须是关联查询。
         */
        none(0);

        @Getter
        private final int intLevel;

        public static String bizCodeByLevelAndBizCodeUnderLineStr(BizCodeLevel bizCodeLevel, Scope scope, String bizCodeUnderLineStr) {

            if (StrUtil.isBlank(bizCodeUnderLineStr)) {
                throw new RuntimeException("业务身份错误");
            }

            Level level = Scope.levelByAnnotation(bizCodeLevel, scope);

            if (StrUtil.equalsIgnoreCase(bizCodeUnderLineStr, "SYSTEM-USER-INFO")) {
                if (scope.isWrite()) {
                    throw new RuntimeException("当前业务身份不允许作数据保存操作.");
                }
                return null;
            }

            if (level == null || level == full || level == tenant) {
                return bizCodeUnderLineStr;
            }

            if (level == none) {
                return scope.isWrite() ? bizCodeUnderLineStr : null;
            }

            int intLevel = level.getIntLevel();

            String[] split = StrUtil.split(bizCodeUnderLineStr, UNDER_LINE);

            if (split.length < intLevel) {
                throw new RuntimeException("业务身份配置错误");
            }

            String[] bizCodeArr = new String[intLevel];

            System.arraycopy(split, 0, bizCodeArr, 0, intLevel);

            return String.join(UNDER_LINE, bizCodeArr);
        }
    }

    enum Scope {
        /**
         * 写
         */
        write,
        /**
         * 读
         */
        query;

        public boolean isWrite() {
            return this == Scope.write;
        }

        public static Level levelByAnnotation(BizCodeLevel bizCodeLevel, Scope scope) {

            if (bizCodeLevel == null || scope == null) {
                return Level.full;
            }

            if (scope == write) {
                return bizCodeLevel.write();
            }

            if (scope == query) {
                return bizCodeLevel.query();
            }

            return Level.full;
        }
    }
}
